/* 
 * File:   MundoSBS.cpp
 * Author: lucia
 * 
 * Created on 6 de octubre de 2014, 19:24
 */

#include "MundoSBS.h"
using namespace std;

MundoSBS::MundoSBS() {
    this->myLogFile->getInstance(MY_LOG_MODE);
    this->playerCounter = 1;
    system("rm -r Doc/PlayerFiles");
    myLogFile->writeInLog(2, "[2] - No se pudo eliminar el directorio./n");
    system("mkdir Doc/PlayerFiles");
    myLogFile->writeInLog(1, "[1] - Se elimino correctamente el directorio de archivos de jugadores./n");
    this->contadorPAU = 0;
    this->theBoss = NULL;
    this->readyToReload = false;
    this->reloadLevel = false;
    this->reloadGame = 0; // nivel inicial sin relodear
    //    this->muertos = 0;
    this->marioAvailable = true;
    this->yoshiAvailable = true;
    this->luigiAvailable = true;
    this->tazAvailable = true;
}

MundoSBS::MundoSBS(const MundoSBS& orig) {
}

MundoSBS::~MundoSBS() {
    //    cout << "Destructor mundoSBS" << endl;
    this->server.close();
    this->running = false;
    delete this->objFact;

}

void sigchld_handler(int s) {
    while (wait(NULL) > 0);
}

void MundoSBS::initData(int argc, char** args) {

    char* nameFileJSON = args[1]; //nombre del archivo que pasan por linea de comando.
    if (argc > 1) {
        //tengo argumentos 
        ifstream myjfile(nameFileJSON, ios::out | ios::binary);
        if (myjfile.fail()) {
            //no existe el archivo
            myLogFile->writeInLog(1, "[1] El parametro informado no se corresponde con un nombre de archivo existente.\n");
            ofstream myJSONFile;
            myJSONFile.open(nameFileJSON, ios_base::app);
            // Or build the object manually
            JSON::Object obj;

            obj["nombre"] = GAME_NAME;
            obj["gravedad"] = WORLD_GRAVITY;

            JSON::Object o, o1;

            o1["x"] = CHARACTER_POSITION_X;
            o1["y"] = CHARACTER_POSITION_Y;

            o["anchoPx"] = SCREEN_WIDTH;
            o["altoPx"] = SCREEN_HEIGHT;
            o["anchoUn"] = DEFAULT_LOGICAL_W;
            o["altoUn"] = DEFAULT_LOGICAL_H;
            o["fondo"] = SCREEN_BACKGROUND;
            o["personaje"] = o1;

            obj["escenario"] = o;

            //Objetos
            JSON::Object fig, fig1, fig2;

            fig["tipo"] = "RECTANGLE";
            fig["x"] = 50;
            fig["y"] = 100;
            fig["alto"] = 10;
            fig["ancho"] = 50;
            fig["color"] = "#AA05B8";
            fig["rot"] = 0.0;
            fig["masa"] = 2;
            fig["estatico"] = true;

            fig1["tipo"] = "RECTANGLE";
            fig1["x"] = 100;
            fig1["y"] = 200;
            fig1["alto"] = 20;
            fig1["ancho"] = 80;
            fig1["color"] = "#AA05B8";
            fig1["rot"] = 0.0;
            fig1["masa"] = 2;
            fig1["estatico"] = true;

            fig2["tipo"] = "PARALLELLOGRAM";
            fig2["x"] = 100;
            fig2["y"] = 200;
            fig2["alto"] = 20;
            fig2["ancho"] = 80;
            fig2["color"] = "#AA05B8";
            fig2["rot"] = 0.0;
            fig2["masa"] = 2;
            fig2["estatico"] = true;

            JSON::Array a;
            a.push_back(fig);
            a.push_back(fig1);
            a.push_back(fig2);

            obj["objetos"] = a;

            //            cout << obj << endl;
            myJSONFile << obj;
        }//fin de no existe el archivo
    }
    if (argc <= 1) {
        nameFileJSON = (char*) "Doc/configuration.json";

        myLogFile->writeInLog(0, "[0] No se recibieron parametros en la ejecucion, se cargara el juego a partir del archivo JSON default.\n");
    }
    ifstream myjfile(nameFileJSON, ios::out | ios::binary);
    if (myjfile.good()) {
        //        printf("Se cargo OK\n");
        //Datos JSON.
        FileWindow *ventanaArch = new FileWindow(nameFileJSON);
        this->data = ventanaArch;
        this->maxPlayers = this->data->getMaxPlayers();
    }
}

void MundoSBS::initData2(int argc, char** args) {

    char* nameFileJSON = args[1]; //nombre del archivo que pasan por linea de comando.
    if (argc > 1) {
        //tengo argumentos 
        ifstream myjfile(nameFileJSON, ios::out | ios::binary);
        if (myjfile.fail()) {
            //no existe el archivo
            myLogFile->writeInLog(1, "[1] El parametro informado no se corresponde con un nombre de archivo existente.\n");
            ofstream myJSONFile;
            myJSONFile.open(nameFileJSON, ios_base::app);
            // Or build the object manually
            JSON::Object obj;

            obj["nombre"] = GAME_NAME;
            obj["gravedad"] = WORLD_GRAVITY;

            JSON::Object o, o1;

            o1["x"] = CHARACTER_POSITION_X;
            o1["y"] = CHARACTER_POSITION_Y;

            o["anchoPx"] = SCREEN_WIDTH;
            o["altoPx"] = SCREEN_HEIGHT;
            o["anchoUn"] = DEFAULT_LOGICAL_W;
            o["altoUn"] = DEFAULT_LOGICAL_H;
            o["fondo"] = SCREEN_BACKGROUND;
            o["personaje"] = o1;

            obj["escenario"] = o;

            //Objetos
            JSON::Object fig, fig1, fig2;

            fig["tipo"] = "RECTANGLE";
            fig["x"] = 50;
            fig["y"] = 100;
            fig["alto"] = 10;
            fig["ancho"] = 50;
            fig["color"] = "#AA05B8";
            fig["rot"] = 0.0;
            fig["masa"] = 2;
            fig["estatico"] = true;

            fig1["tipo"] = "RECTANGLE";
            fig1["x"] = 100;
            fig1["y"] = 200;
            fig1["alto"] = 20;
            fig1["ancho"] = 80;
            fig1["color"] = "#AA05B8";
            fig1["rot"] = 0.0;
            fig1["masa"] = 2;
            fig1["estatico"] = true;

            fig2["tipo"] = "PARALLELLOGRAM";
            fig2["x"] = 100;
            fig2["y"] = 200;
            fig2["alto"] = 20;
            fig2["ancho"] = 80;
            fig2["color"] = "#AA05B8";
            fig2["rot"] = 0.0;
            fig2["masa"] = 2;
            fig2["estatico"] = true;

            JSON::Array a;
            a.push_back(fig);
            a.push_back(fig1);
            a.push_back(fig2);

            obj["objetos"] = a;

            //            cout << obj << endl;
            myJSONFile << obj;
        }//fin de no existe el archivo
    }
    if (argc <= 1) {
        nameFileJSON = (char*) "Doc/configuration2.json";

        myLogFile->writeInLog(0, "[0] No se recibieron parametros en la ejecucion, se cargara el juego a partir del archivo JSON default.\n");
    }
    ifstream myjfile(nameFileJSON, ios::out | ios::binary);
    if (myjfile.good()) {
        //        printf("Se cargo OK\n");
        //Datos JSON.
        FileWindow *ventanaArch = new FileWindow(nameFileJSON);
        this->data2 = ventanaArch;
    }
}

void MundoSBS::initGame() {

    int tam = this->worldObjects.size();
    for (int i = 0; i < tam; i++) {
        this->worldObjects.pop_back();
    }

    this->theBoss = NULL;

    int ubicDyn = this->dynamicBodys.size();

    //RECTANGLE
    vector<FileObjects>* fileRectangle = this->data->getRectangle();
    if (fileRectangle->size() != 0) {
        for (int i = 0; i < fileRectangle->size(); i++) {
            Rectangle *unRectangulo = new Rectangle(objFact, fileRectangle->at(i).isStatic(), fileRectangle->at(i).getXCoordinate(), fileRectangle->at(i).getYCoordinate(), fileRectangle->at(i).getWidth(), fileRectangle->at(i).getHeight(), fileRectangle->at(i).getMass(), fileRectangle->at(i).getRotation(), fileRectangle->at(i).getFigureTextureID());

            if (fileRectangle->at(i).isStatic()) {
                this->staticBodys.push_back(unRectangulo);
            } else {
                // si vec 0-n => size n+1 .. n+1 va a ser la nueva pos del elem pusheado            
                unRectangulo->setUbicDyn(ubicDyn);
                this->dynamicBodys.push_back(unRectangulo);
                ubicDyn++;
            }

            this->worldObjects.push_back(unRectangulo->getData());
        }
    } else {
        myLogFile->writeInLog(0, "[0] No hay rectangulos cargados o no pasaron el filtro.\n");
    }
    //    cout << "fiiiiiiiiiiiiiiiiinn herectttttttttttttn" << endl;

    //PARALLELLOGRAM
    vector<FileObjects>* fileParallellogram = this->data->getParrallellogram();
    if (fileParallellogram->size() != 0) {
        for (int i = 0; i < fileParallellogram->size(); i++) {
            Parallellogram *unParalelogramo = new Parallellogram(objFact, fileParallellogram->at(i).isStatic(), fileParallellogram->at(i).getXCoordinate(), fileParallellogram->at(i).getYCoordinate(), fileParallellogram->at(i).getBase(), fileParallellogram->at(i).getHighParall(), fileParallellogram->at(i).getAngle1(), fileParallellogram->at(i).getMass(), fileParallellogram->at(i).getRotation(), fileParallellogram->at(i).getFigureTextureID());
            if (fileParallellogram->at(i).isStatic()) {
                this->staticBodys.push_back(unParalelogramo);
            } else {
                unParalelogramo->setUbicDyn(ubicDyn);
                this->dynamicBodys.push_back(unParalelogramo);
                ubicDyn++;
            }

            this->worldObjects.push_back(unParalelogramo->getData());
        }
    } else {
        myLogFile->writeInLog(0, "[0] No hay paralelogramos cargados o no pasaron el filtro.\n");
    }

    //TRAPEZIUM
    vector<FileObjects>* fileTrapezium = this->data->getTrapezium();
    if (fileTrapezium->size() != 0) {
        for (int i = 0; i < fileTrapezium->size(); i++) {
            Trapezium *unTrapezium = new Trapezium(objFact, fileTrapezium->at(i).isStatic(), fileTrapezium->at(i).getXCoordinate(), fileTrapezium->at(i).getYCoordinate(), fileTrapezium->at(i).getBase(), fileTrapezium->at(i).getHeight(), fileTrapezium->at(i).getAngle1(), fileTrapezium->at(i).getAngle2(), fileTrapezium->at(i).getMass(), fileTrapezium->at(i).getRotation(), fileTrapezium->at(i).getFigureTextureID());
            if (fileTrapezium->at(i).isStatic()) {
                this->staticBodys.push_back(unTrapezium);
            } else {
                unTrapezium->setUbicDyn(ubicDyn);
                this->dynamicBodys.push_back(unTrapezium);
                ubicDyn++;
            }
            this->worldObjects.push_back(unTrapezium->getData());
        }
    } else {
        myLogFile->writeInLog(0, "[0] No hay trapecios cargados o no pasaron el filtro.\n");
    }

    //CIRCLE
    vector<FileObjects>* fileCircle = this->data->getCircle();
    if (fileCircle->size() != 0) {
        for (int i = 0; i < fileCircle->size(); i++) {
            Circle *unCircle = new Circle(objFact, fileCircle->at(i).isStatic(), fileCircle->at(i).getXCoordinate(), fileCircle->at(i).getYCoordinate(), fileCircle->at(i).getScale(), fileCircle->at(i).getMass(), fileCircle->at(i).getFigureTextureID());

            if (fileCircle->at(i).isStatic()) {
                this->staticBodys.push_back(unCircle);
            } else {
                unCircle->setUbicDyn(ubicDyn);
                this->dynamicBodys.push_back(unCircle);
                ubicDyn++;
            }
            this->worldObjects.push_back(unCircle->getData());
        }
    } else {
        myLogFile->writeInLog(0, "[0] No hay circulos cargados o no pasaron el filtro.\n");
    }
    //    cout << "fiiiiiiiiiiiiiiiiinn circle" << endl;

    //TRIÁNGULO
    vector<FileObjects>* fileTriangulo = this->data->getPolygon(3);
    if (fileTriangulo->size() != 0) {
        for (int i = 0; i < fileTriangulo->size(); i++) {
            Polygon *unTriangulo = new Polygon(objFact, fileTriangulo->at(i).isStatic(), fileTriangulo->at(i).getXCoordinate(), fileTriangulo->at(i).getYCoordinate(), fileTriangulo->at(i).getScale(), fileTriangulo->at(i).getSides(), fileTriangulo->at(i).getMass(), fileTriangulo->at(i).getRotation(), fileTriangulo->at(i).getFigureTextureID());
            if (fileTriangulo->at(i).isStatic()) {
                this->staticBodys.push_back(unTriangulo);
            } else {
                unTriangulo->setUbicDyn(ubicDyn);
                this->dynamicBodys.push_back(unTriangulo);
                ubicDyn++;
            }
            this->worldObjects.push_back(unTriangulo->getData());
        }
    } else {
        myLogFile->writeInLog(0, "[0] No hay triangulos cargados o no pasaron el filtro.\n");
    }

    //POLYGON de 5 lados
    vector<FileObjects>* filePolygonFive = this->data->getPolygon(5);
    if (filePolygonFive->size() != 0) {
        for (int i = 0; i < filePolygonFive->size(); i++) {
            Polygon *unPolygono = new Polygon(objFact, filePolygonFive->at(i).isStatic(), filePolygonFive->at(i).getXCoordinate(), filePolygonFive->at(i).getYCoordinate(), filePolygonFive->at(i).getScale(), filePolygonFive->at(i).getSides(), filePolygonFive->at(i).getMass(), filePolygonFive->at(i).getRotation(), filePolygonFive->at(i).getFigureTextureID());
            if (filePolygonFive->at(i).isStatic()) {
                this->staticBodys.push_back(unPolygono);
            } else {
                unPolygono->setUbicDyn(ubicDyn);
                this->dynamicBodys.push_back(unPolygono);
                ubicDyn++;
            }
            this->worldObjects.push_back(unPolygono->getData());
        }
    } else {
        myLogFile->writeInLog(0, "[0] No hay poligonos (5) cargados o no pasaron el filtro.\n");
    }
    //    cout << "fiiiiiiiiiiiiiiiiinn hexagon" << endl;

    //POLYGON de 6 lados
    vector<FileObjects>* filePolygonSix = this->data->getPolygon(6);
    if (filePolygonSix->size() != 0) {
        for (int i = 0; i < filePolygonSix->size(); i++) {
            Polygon *unPolygono = new Polygon(objFact, filePolygonSix->at(i).isStatic(), filePolygonSix->at(i).getXCoordinate(), filePolygonSix->at(i).getYCoordinate(), filePolygonSix->at(i).getScale(), filePolygonSix->at(i).getSides(), filePolygonSix->at(i).getMass(), filePolygonSix->at(i).getRotation(), filePolygonSix->at(i).getFigureTextureID());
            if (filePolygonSix->at(i).isStatic()) {
                this->staticBodys.push_back(unPolygono);
            } else {
                unPolygono->setUbicDyn(ubicDyn);
                this->dynamicBodys.push_back(unPolygono);
                ubicDyn++;
            }
            this->worldObjects.push_back(unPolygono->getData());
        }
    } else {
        myLogFile->writeInLog(0, "[0] No hay poligonos (6) cargados o no pasaron el filtro.\n");
    }

    //    cout << "fiiiiiiiiiiiiiiiiinn hexagon" << endl;

    //    ENEMY fireShooterEnemy
    //             #TODO ->CREO UN MALO Y LO PUSHEO, ESTO DEBERIA ENTRAR POR JSON SUPONGO
    FireShooterEnemy *fireShooterEnemy = new FireShooterEnemy(objFact, 800, 1800);
    fireShooterEnemy->setUbicDyn(ubicDyn);
    this->dynamicBodys.push_back(fireShooterEnemy);
    ubicDyn++;
    this->fireShooterEnemy.push_back(fireShooterEnemy);
    this->worldObjects.push_back(fireShooterEnemy->getData());

    FireShooterEnemy *fireShooterEnemy2 = new FireShooterEnemy(objFact, 800, 500);
    fireShooterEnemy2->setUbicDyn(ubicDyn);
    this->dynamicBodys.push_back(fireShooterEnemy2);
    ubicDyn++;
    this->fireShooterEnemy.push_back(fireShooterEnemy2);
    this->worldObjects.push_back(fireShooterEnemy2->getData());

    // ENEMY StandardEnemy
    StandardEnemy *standardEnemy = new StandardEnemy(objFact, 800, 1800);
    standardEnemy->setUbicDyn(ubicDyn);
    this->dynamicBodys.push_back(standardEnemy);
    ubicDyn++;
    this->standardEnemy.push_back(standardEnemy);
    this->worldObjects.push_back(standardEnemy->getData());

    StandardEnemy *standardEnemy1 = new StandardEnemy(objFact, 800, 500);
    standardEnemy1->setUbicDyn(ubicDyn);
    this->dynamicBodys.push_back(standardEnemy1);
    ubicDyn++;
    this->standardEnemy.push_back(standardEnemy1);
    this->worldObjects.push_back(standardEnemy1->getData());

    ////    //Creo los bonus (se reutilizan) 
    //    for (int i = 0; i < 2; i++) {
    //        int typeBonus = 1 + (rand() % 2);
    //        Bonus* unBonus = new Bonus(objFact, typeBonus, -100, -100);
    //        unBonus->setUbicDyn(ubicDyn);
    //        this->dynamicBodys.push_back(unBonus);
    //        ubicDyn++;
    //        this->bonus.push_back(unBonus);
    //        this->worldObjects.push_back(unBonus->getData());
    //    }

    Bonus* unBonus1 = new Bonus(objFact, 1, -100, -100);
    unBonus1->setUbicDyn(ubicDyn);
    this->dynamicBodys.push_back(unBonus1);
    ubicDyn++;
    this->bonus.push_back(unBonus1);
    this->worldObjects.push_back(unBonus1->getData());

    Bonus* unBonus2 = new Bonus(objFact, 2, -100, -100);
    unBonus2->setUbicDyn(ubicDyn);
    this->dynamicBodys.push_back(unBonus2);
    ubicDyn++;
    this->bonus.push_back(unBonus2);
    this->worldObjects.push_back(unBonus2->getData());

    //    cout << "cargo los jugadores " << endl;
    WorldElement* player1 = NULL;
    WorldElement* player2 = NULL;
    int tam3 = auxPlayers.size();
    for (int i = 0; i < tam3; i++) {
        WorldElement* unElem = auxPlayers.back();
        auxPlayers.pop_back();
        if (unElem->getData().idCharacter == 1) {
            player1 = unElem;
        }
        if (unElem->getData().idCharacter == 2) {
            player2 = unElem;
        }

    }
    if (player1 != NULL) {
        this->dynamicBodys.push_back(player1);
        player1->setUbicDyn(ubicDyn);
        ubicDyn++;
        this->worldObjects.push_back(player1->getData());
    }
    if (player2 != NULL) {
        this->dynamicBodys.push_back(player2);
        player2->setUbicDyn(ubicDyn);
        ubicDyn++;
        this->worldObjects.push_back(player2->getData());
    }

    //    cout << "this->dynamicBodys sizeeeeeeeeeeeee   " << this->dynamicBodys.size() << endl;
    //    cout << "this->staticBodys sizeeeeeeeeeeeee   " << this->staticBodys.size() << endl;
}

void MundoSBS::initGame2() {

    int ubicDyn = this->dynamicBodys.size();

    //RECTANGLE
    vector<FileObjects>* fileRectangle = this->data2->getRectangle();
    if (fileRectangle->size() != 0) {
        for (int i = 0; i < fileRectangle->size(); i++) {
            //            cout << "rectangle" << endl;
            Rectangle *unRectangulo = new Rectangle(objFact, fileRectangle->at(i).isStatic(), fileRectangle->at(i).getXCoordinate(), fileRectangle->at(i).getYCoordinate(), fileRectangle->at(i).getWidth(), fileRectangle->at(i).getHeight(), fileRectangle->at(i).getMass(), fileRectangle->at(i).getRotation(), fileRectangle->at(i).getFigureTextureID());

            if (fileRectangle->at(i).isStatic()) {
                this->staticBodys.push_back(unRectangulo);
            } else {
                // si vec 0-n => size n+1 .. n+1 va a ser la nueva pos del elem pusheado            
                unRectangulo->setUbicDyn(ubicDyn);
                this->dynamicBodys.push_back(unRectangulo);
                ubicDyn++;
            }
        }
    } else {
        myLogFile->writeInLog(0, "[0] No hay rectangulos cargados o no pasaron el filtro.\n");
    }

    //PARALLELLOGRAM
    vector<FileObjects>* fileParallellogram = this->data2->getParrallellogram();
    if (fileParallellogram->size() != 0) {
        for (int i = 0; i < fileParallellogram->size(); i++) {
            Parallellogram *unParalelogramo = new Parallellogram(objFact, fileParallellogram->at(i).isStatic(), fileParallellogram->at(i).getXCoordinate(), fileParallellogram->at(i).getYCoordinate(), fileParallellogram->at(i).getBase(), fileParallellogram->at(i).getHighParall(), fileParallellogram->at(i).getAngle1(), fileParallellogram->at(i).getMass(), fileParallellogram->at(i).getRotation(), fileParallellogram->at(i).getFigureTextureID());
            if (fileParallellogram->at(i).isStatic()) {
                this->staticBodys.push_back(unParalelogramo);
            } else {
                unParalelogramo->setUbicDyn(ubicDyn);
                this->dynamicBodys.push_back(unParalelogramo);
                ubicDyn++;
            }
        }
    } else {
        myLogFile->writeInLog(0, "[0] No hay paralelogramos cargados o no pasaron el filtro.\n");
    }

    //TRAPEZIUM
    vector<FileObjects>* fileTrapezium = this->data2->getTrapezium();
    if (fileTrapezium->size() != 0) {
        for (int i = 0; i < fileTrapezium->size(); i++) {
            Trapezium *unTrapezium = new Trapezium(objFact, fileTrapezium->at(i).isStatic(), fileTrapezium->at(i).getXCoordinate(), fileTrapezium->at(i).getYCoordinate(), fileTrapezium->at(i).getBase(), fileTrapezium->at(i).getHeight(), fileTrapezium->at(i).getAngle1(), fileTrapezium->at(i).getAngle2(), fileTrapezium->at(i).getMass(), fileTrapezium->at(i).getRotation(), fileTrapezium->at(i).getFigureTextureID());
            if (fileTrapezium->at(i).isStatic()) {
                this->staticBodys.push_back(unTrapezium);
            } else {
                unTrapezium->setUbicDyn(ubicDyn);
                this->dynamicBodys.push_back(unTrapezium);
                ubicDyn++;
            }
        }
    } else {
        myLogFile->writeInLog(0, "[0] No hay trapecios cargados o no pasaron el filtro.\n");
    }


    //CIRCLE
    vector<FileObjects>* fileCircle = this->data2->getCircle();
    if (fileCircle->size() != 0) {
        for (int i = 0; i < fileCircle->size(); i++) {
            Circle *unCircle = new Circle(objFact, fileCircle->at(i).isStatic(), fileCircle->at(i).getXCoordinate(), fileCircle->at(i).getYCoordinate(), fileCircle->at(i).getScale(), fileCircle->at(i).getMass(), fileCircle->at(i).getFigureTextureID());

            if (fileCircle->at(i).isStatic()) {
                this->staticBodys.push_back(unCircle);
            } else {
                unCircle->setUbicDyn(ubicDyn);
                this->dynamicBodys.push_back(unCircle);
                ubicDyn++;
            }
        }
    } else {
        myLogFile->writeInLog(0, "[0] No hay circulos cargados o no pasaron el filtro.\n");
    }

    //TRIÁNGULO
    vector<FileObjects>* fileTriangulo = this->data2->getPolygon(3);
    if (fileTriangulo->size() != 0) {
        for (int i = 0; i < fileTriangulo->size(); i++) {
            Polygon *unTriangulo = new Polygon(objFact, fileTriangulo->at(i).isStatic(), fileTriangulo->at(i).getXCoordinate(), fileTriangulo->at(i).getYCoordinate(), fileTriangulo->at(i).getScale(), fileTriangulo->at(i).getSides(), fileTriangulo->at(i).getMass(), fileTriangulo->at(i).getRotation(), fileTriangulo->at(i).getFigureTextureID());
            if (fileTriangulo->at(i).isStatic()) {
                this->staticBodys.push_back(unTriangulo);
            } else {
                unTriangulo->setUbicDyn(ubicDyn);
                this->dynamicBodys.push_back(unTriangulo);
                ubicDyn++;
            }
        }
    } else {
        myLogFile->writeInLog(0, "[0] No hay triangulos cargados o no pasaron el filtro.\n");
    }


    //POLYGON de 5 lados
    vector<FileObjects>* filePolygonFive = this->data2->getPolygon(5);
    if (filePolygonFive->size() != 0) {
        for (int i = 0; i < filePolygonFive->size(); i++) {
            Polygon *unPolygono = new Polygon(objFact, filePolygonFive->at(i).isStatic(), filePolygonFive->at(i).getXCoordinate(), filePolygonFive->at(i).getYCoordinate(), filePolygonFive->at(i).getScale(), filePolygonFive->at(i).getSides(), filePolygonFive->at(i).getMass(), filePolygonFive->at(i).getRotation(), filePolygonFive->at(i).getFigureTextureID());
            if (filePolygonFive->at(i).isStatic()) {
                this->staticBodys.push_back(unPolygono);
            } else {
                unPolygono->setUbicDyn(ubicDyn);
                this->dynamicBodys.push_back(unPolygono);
                ubicDyn++;
            }
        }
    } else {
        myLogFile->writeInLog(0, "[0] No hay poligonos (5) cargados o no pasaron el filtro.\n");
    }

    //POLYGON de 6 lados
    vector<FileObjects>* filePolygonSix = this->data2->getPolygon(6);
    if (filePolygonSix->size() != 0) {
        for (int i = 0; i < filePolygonSix->size(); i++) {
            Polygon *unPolygono = new Polygon(objFact, filePolygonSix->at(i).isStatic(), filePolygonSix->at(i).getXCoordinate(), filePolygonSix->at(i).getYCoordinate(), filePolygonSix->at(i).getScale(), filePolygonSix->at(i).getSides(), filePolygonSix->at(i).getMass(), filePolygonSix->at(i).getRotation(), filePolygonSix->at(i).getFigureTextureID());
            if (filePolygonSix->at(i).isStatic()) {
                this->staticBodys.push_back(unPolygono);
            } else {
                unPolygono->setUbicDyn(ubicDyn);
                this->dynamicBodys.push_back(unPolygono);
                ubicDyn++;
            }
        }
    } else {
        myLogFile->writeInLog(0, "[0] No hay poligonos (6) cargados o no pasaron el filtro.\n");
    }

    //    ENEMY fireShooterEnemy
    //             #TODO ->CREO UN MALO Y LO PUSHEO, ESTO DEBERIA ENTRAR POR JSON SUPONGO
    FireShooterEnemy *fireShooterEnemy = new FireShooterEnemy(objFact, 800, 1800);
    fireShooterEnemy->setUbicDyn(ubicDyn);
    this->dynamicBodys.push_back(fireShooterEnemy);
    ubicDyn++;
    this->fireShooterEnemy.push_back(fireShooterEnemy);
    //
    FireShooterEnemy *fireShooterEnemy2 = new FireShooterEnemy(objFact, 800, 500);
    fireShooterEnemy2->setUbicDyn(ubicDyn);
    this->dynamicBodys.push_back(fireShooterEnemy2);
    ubicDyn++;
    this->fireShooterEnemy.push_back(fireShooterEnemy2);

    // ENEMY StandardEnemy
    StandardEnemy *standardEnemy = new StandardEnemy(objFact, 800, 1800);
    standardEnemy->setUbicDyn(ubicDyn);
    this->dynamicBodys.push_back(standardEnemy);
    ubicDyn++;
    this->standardEnemy.push_back(standardEnemy);

    StandardEnemy *standardEnemy1 = new StandardEnemy(objFact, 850, 500);
    standardEnemy1->setUbicDyn(ubicDyn);
    this->dynamicBodys.push_back(standardEnemy1);
    ubicDyn++;
    this->standardEnemy.push_back(standardEnemy1);
    //    //    Creo los bonus (se reutilizan) 
    for (int i = 0; i < CANT_BONUS; i++) {
        int typeBonus = 1 + (rand() % 2);
        Bonus* unBonus = new Bonus(objFact, typeBonus, -100, -100);
        unBonus->setUbicDyn(ubicDyn);
        this->dynamicBodys.push_back(unBonus);
        ubicDyn++;
        this->bonus.push_back(unBonus);
    }

    Boss *boss = new Boss(objFact, 3000, 1000);
    boss->setUbicDyn(ubicDyn);
    this->dynamicBodys.push_back(boss);
    ubicDyn++;
    this->theBoss = boss;

    //    cout << "cargo los jugadores " << endl;
    int tam3 = auxPlayers.size();
    for (int i = 0; i < tam3; i++) {
        WorldElement* unElem = auxPlayers.back();
        auxPlayers.pop_back();
        this->dynamicBodys.push_back(unElem);
        unElem->setUbicDyn(ubicDyn);
        ubicDyn++;
    }
    //    cout << "END this->staticBodys.size(): " << this->staticBodys.size() << endl;
    //    cout << "END this->dynamicBodys.size():" << this->dynamicBodys.size() << endl;
    //    cout << "FIN- NUEVO MUNDO BOX2D cant bodies: " << this->world->GetBodyCount() << endl;
}

void MundoSBS::makeBossMove() {

    if (this->theBoss != NULL) {
        this->theBoss->beRandom();
        //agrega enemigos al mapa.
        if (this->theBoss->getState() == ATTACKING) { //cambiar la probabilidad de esto para que entre mas seguido.
            //            agrego enemigos, una cantidad random.
            int randomNumber = rand() % 100;
            if (randomNumber == 0) {
                //creo un nuevo enemigo y lo agrego al mundo
                //                cout << "enemigo nuevo" << endl;
                StandardEnemy *standardEnemy = new StandardEnemy(objFact, 2350, 900);
                standardEnemy->setUbicDyn(this->dynamicBodys.size());
                this->dynamicBodys.push_back(standardEnemy);
                this->standardEnemy.push_back(standardEnemy);
            }
        }
    }
    if (this->theBoss != NULL) {
        //#NOTA: Agregar contacto con una crazy ball.
        if (this->theBoss->inConctactBullet()) {
            //RECIBIR disparos.
            this->theBoss->beAttacked();
        }
    }
}

void MundoSBS::makeEnemiesMove() {
    //movimiento de FireShooterEnemy    
    for (int i = 0; i < this->fireShooterEnemy.size(); i++) {
        FireShooterEnemy *fireShooterEnemy = this->fireShooterEnemy.at(i);
        fireShooterEnemy->walk();
        if (fireShooterEnemy->tryToDelete()) {
            //            int pn = (1 / PROBA_BONUS);
            //            int randomNumber = rand() % pn;
            //            if (randomNumber == 0) {
            this->addNewBonus(fireShooterEnemy->getPosToBonusX(), fireShooterEnemy->getPosToBonusY());
            //            }
        }
        if (!fireShooterEnemy->isCaught() && fireShooterEnemy->alive) {
            FireBall* fireBall = fireShooterEnemy->shootRandom();
            if (fireBall != NULL) {
                fireBall->getShape()->setUbicDyn(this->bulletsList.size());
                this->bulletsList.push_back(fireBall);
                //                cout << "PUSH" << endl;
            }
        }
    }
    //    movimiento de FireShooterEnemy    
    for (int i = 0; i < this->standardEnemy.size(); i++) {
        StandardEnemy *standardEnemy = this->standardEnemy.at(i);
        standardEnemy->walk();
        if (standardEnemy->tryToDelete()) {
            //            int pn = (1 / PROBA_BONUS);
            //            int randomNumber = rand() % pn;
            //            if (randomNumber == 0) {
            this->addNewBonus(standardEnemy->getPosToBonusX(), standardEnemy->getPosToBonusY());
            //            }
        }
    }
    for (int i = 0; i< this->fireShooterEnemy.size(); i++) {
        Enemy *enemy = this->fireShooterEnemy.at(i);
        if (enemy->inConctactBullet()) { //en contacto con una pelota
            //stop
            enemy->beCaught();
        }


        if (enemy->inConctactCrazyBall()) {
            //            cout << "contact crazy ball" << endl;
            this->killEnemy(enemy);
        }
        //        cout << "endl contact crazy"<<endl;     
        if (enemy->toKick()) {
            enemy->setCrazyBall();
        }

        if (enemy->isCrazyBall()) {
            enemy->checkContacts(); // cambia la imagen de la crazy ball
        }

    }
    for (int i = 0; i< this->standardEnemy.size(); i++) {
        Enemy *enemy = this->standardEnemy.at(i);
        if (enemy->inConctactBullet()) { //en contacto con una pelota
            //stop
            enemy->beCaught();
        }
        if (enemy->inConctactCrazyBall()) {
            //            cout << "contact crazy ball" << endl;
            this->killEnemy(enemy);
        }
        //        cout << "endl contact crazy"<<endl;     

        if (enemy->toKick()) {
            enemy->setCrazyBall();
        }

        if (enemy->isCrazyBall()) {
            enemy->checkContacts(); // cambia la imagen de la crazy ball
        }
    }
}

bool MundoSBS::areEnemiesAlive() {

    bool areAlive = false;
    for (int i = 0; i < this->fireShooterEnemy.size(); i++) {
        if (this->fireShooterEnemy.at(i)->alive) {
            areAlive = true;
        }
    }
    for (int i = 0; i < this->standardEnemy.size(); i++) {
        if (this->standardEnemy.at(i)->alive) {
            areAlive = true;
        }
    }
    return areAlive;

    //        this->contadorPAU++;
    //        //        cout << "contador Pau" << this->contadorPAU << endl;
    //        if (contadorPAU > 30000) {
    //            contadorPAU = 0;
    //            return false;
    //        }
    //        return true;
}

bool MundoSBS::isBossAlive() {
    if (this->theBoss != NULL) {
        return this->theBoss->isAlive();
    }
    return true;

    //    this->contadorPAU++;
    //    //        cout << "contador Pau" << this->contadorPAU << endl;
    //    if (contadorPAU > 600) {
    //        contadorPAU = 0;
    //        return false;
    //    }
    //    return true;

}

void MundoSBS::resetPlayers() {
    for (list <Player*>::iterator it = this->players.begin(); it != this->players.end(); ++it) {
        Player *itPlayer = *it;
        itPlayer->restartPlayer();
    }
}

void MundoSBS::erasePlayersNotInit() {

    bool end = false;
    while (!end) {

        bool toDelete = false;
        for (list <Player*>::iterator it = this->players.begin(); it != this->players.end(); ++it) {
            Player *itPlayer = *it;
            if (!(itPlayer->isInit())) {
                this->players.erase(it);
                toDelete = true;
                break;
            }
        }

        // si hubo algo para borrar, puede que haya otro no init
        if (!(toDelete)) {
            end = true;
        }
    }

}

void MundoSBS::killBodyPlayer(Player * player) {
    if (player->hasBody()) {
        this->world->DestroyBody(player->getBody());
        player->setHasBody(false);
        if (player->getCharacterId() == 1) {
            this->marioAvailable = true;
        } else if (player->getCharacterId() == 2) {
            this->yoshiAvailable = true;
        } else if (player->getCharacterId() == 3) {
            this->luigiAvailable = true;
        } else if (player->getCharacterId() == 4) {
            this->tazAvailable = true;
        }
    }
}

struct Element MundoSBS::reloadPlayer(string name) {

    SBSLog* myLogFile;
    struct Element myPlayer;
    string fileName;
    fileName.append("Doc/PlayerFiles/player");
    fileName.append(name);
    fileName.append(".json");
    //    cout << "fileName: " << fileName << endl;
    myLogFile->getInstance(MY_LOG_MODE);
    myLogFile->writeInLog(0, "[0] Se inicia el parseo del archivo del jugador.\n");
    try {
        JSON::Value fileMap = parse_file(fileName.c_str());
        if (fileMap["personaje"].type() == JSON::OBJECT) {
            JSON::Object nivel = ((fileMap["personaje"]).operator JSON::Object());
            myLogFile->writeInLog(0, "[0] El TAG personaje correctamente definido, se procede a parsear los atributos del personaje.\n");
            if (nivel["id"].type() == JSON::INT) {
                myPlayer.id = ((nivel["id"]).as_int());
                myLogFile->writeInLog(0, "[0] Se parseo el id del jugador exitosamente\n");
            } else {
                myLogFile->writeInLog(1, "[1] El id del jugador no esta en el archivo o no tiene un valor valido.\n");
            }
            if (nivel["ubic"].type() == JSON::INT) {
                myPlayer.ubic = ((nivel["ubic"]).as_int()); // cambiar this->number por la posx del player
                myLogFile->writeInLog(0, "[0] Se parseo la ubicacion dinamica exitosamente\n");
            } else {
                myLogFile->writeInLog(1, "[1] La ubicacion dinamica del jugador no esta en el archivo o no tiene un valor valido.\n");

            }
            if (nivel["x"].type() == JSON::INT) {
                myPlayer.x = ((nivel["x"]).as_int()); // cambiar this->number por la posx del player
                myLogFile->writeInLog(0, "[0] Se parseo la posicion x del jugador exitosamente\n");
            } else {
                myLogFile->writeInLog(1, "[1] La posicion x del jugador no esta en el archivo o no tiene un valor valido.\n");

            }
            if (nivel["y"].type() == JSON::INT) {
                myPlayer.y = ((nivel["y"]).as_int()); // cambiar this->number por la posy del player
                myLogFile->writeInLog(0, "[0] Se parseo la posicion y del jugador exitosamente\n");
            } else {
                myLogFile->writeInLog(1, "[1] La posicion y del jugador no esta en el archivo o no tiene un valor valido.\n");
            }
            //Destaguear esto cuando se implemente la entrega 3
            //            if (nivel["points"].type() == JSON::INT) { // cambiar this->number por los puntos del player
            //                this->number = ((nivel["points"]).as_int());
            //                myLogFile->writeInLog(0, "[0] Se parseo la cantidad de puntos acumulados del jugador exitosamente\n");
            //            } else {
            //                myLogFile->writeInLog(1, "[1] La cantidad de puntos acumulados del jugador no esta en el archivo o no tiene un valor valido.\n");
            //            }
            //            if (nivel["lives"].type() == JSON::INT) { // cambiar this->number por las vidas del player
            //                this->number = ((nivel["lives"]).as_int());
            //                myLogFile->writeInLog(0, "[0] Se parseo la cantidad de puntos acumulados del jugador exitosamente\n");
            //            } else {
            //                myLogFile->writeInLog(1, "[1] El ancho en unidades logicas de la ventana no esta en el archivo o no tiene un valor valido.  Se tomara el valor por default DEFAULT_LOGICAL_H\n");
            //            }
        }

        return myPlayer;
    } catch (runtime_error myRE) {
        myLogFile->writeInLog(2, "[2] Se detectaron errores de sintaxis al parsear el archivo JSON.  El error fue el siguiente: ");
        myLogFile->writeInLog(2, myRE.what());
        myLogFile->writeInLog(2, "\n");
    } catch (invalid_argument myIA) {
        myLogFile->writeInLog(2, "[2] Se detecto un error de argumento invalido al parsear el archivo JSON.  El error fue el siguiente: ");
        myLogFile->writeInLog(2, myIA.what());
        myLogFile->writeInLog(2, "\n");
    }

}

void MundoSBS::initServer(char* address, int port) {
    struct sigaction sa; //para limpiar procesos zombis.
    //servidor    
    ServerSocket servidor;
    if (servidor.initSocket() == ERROR) {
        //        cout << "Error initSocket " << endl;
        myLogFile->writeInLog(2, "[2] Se produjo un error interno del socket\n Se cerrará la ejecución\n");
        exit(1);
    }

    int yes = 1;
    if (setsockopt(servidor.getSocket(), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof (int)) == ERROR) {
        //        cout << "setsockopt" << endl;
        myLogFile->writeInLog(2, "[2] Se produjo un error interno del socket\n Se cerrará la ejecución\n");
        exit(1);
    }

    if (servidor.initServer(address, port) == ERROR) {
        //        cout << "error en bind" << endl;
        myLogFile->writeInLog(2, "[2] Error bind, pruebe con otra ip\n Se cerrará la ejecución\n");
        exit(1);
    }

    //conexiones pendientes
    int backLog = 10;
    if (servidor.listen(backLog) == ERROR) {
        //        cout << "Error listen()" << endl;
        myLogFile->writeInLog(2, "[2] Se produjo un error interno del socket\n Se cerrará la ejecución\n");
        exit(1);
    }

    //limpiar procesos zombis.
    sa.sa_handler = sigchld_handler; // Eliminar procesos muertos
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGCHLD, &sa, NULL) == ERROR) {
        //        cout << "sigaction" << endl;
        myLogFile->writeInLog(2, "[2] Se produjo un error durante la eliminación de procesos muertos\n Se cerrará la ejecución\n");
        exit(1);
    }
    this->server = servidor;
}

int MundoSBS::playerAlreadyExist(string name) {
    //devuelve 0,1,2,3,4 --> 0 si no existe el player

    //    if (!this->players.empty()) {
    //        for (list <Player*>::iterator it = this->players.begin(); it != this->players.end(); ++it) {
    //            Player *itPlayer = *it;
    //
    //            if ((name.compare(itPlayer->getName())) == 0 && !(itPlayer->isInit())) {
    //                return itPlayer->getCharacterId();
    //            }
    //        }
    //    }
    //
    return 0; //jugador nuevo
}

bool MundoSBS::playersAreReady() {
    return (this->players.size() == this->maxPlayers);
}

bool MundoSBS::playersReadyToReload() {
    int cont = 0;
    //    cout << this->players.size() << endl;
    for (list <Player*>::iterator it = this->players.begin(); it != this->players.end(); ++it) {
        Player *itPlayer = *it;

        if (itPlayer->isInit()) {
            cont++;
        }
    }

    //si readyToReload --> puede conectarse alguien nuevo 
    if (cont != this->maxPlayers) {
        this->readyToReload = true;
    } else {
        this->readyToReload = false;
    }

    return (cont == this->maxPlayers);
}

void MundoSBS::startConection() {
    //ver si es menor o igual.
    while (this->running) {
        //aceptar conexiones
        int socket = this->server.accept(this->clientAddress);
        if (socket == ERROR) {
            //            cout << "Error- accept() " << endl;
            myLogFile->writeInLog(2, "[2] Error interno del socket al aceptar cliente nuevo. No se tomará en cuenta\n");
            break;

        } else {
            cout << "Conexion de: " << inet_ntoa(this->clientAddress.sin_addr) << endl;
            myLogFile->writeInLog(0, "[0] Se obtuvo conexion de ");
            myLogFile->writeInLog(0, inet_ntoa(this->clientAddress.sin_addr));
            myLogFile->writeInLog(0, "\n");

            // obtengo el nombre del jugador
            struct Jugador myPlayer;
            int myLen = sizeof (myPlayer);

            int n = this->getServer().recvTimeOut(socket, &myPlayer, myLen, 4);
            if (n == ERROR) {
                myLogFile->writeInLog(2, "[2] Error interno del socket al recibir el nombre del cliente. No se tomará en cuenta el jugador\n");
                break;
            }
            if (n == -2) {
                myLogFile->writeInLog(0, "[0] El cliente se desconecto antes de cargar el jugador. No se tomará en cuenta el jugador\n");
                break;
            }
            if (n == 0) {
                // no deberia seguir
                myLogFile->writeInLog(0, "[0] El cliente se desconecto antes de cargar el jugador. No se tomará en cuenta el jugador\n");
                break;
            }

            myLogFile->writeInLog(0, "[0] Se ha conectado el jugador \n");
            myLogFile->writeInLog(0, string(myPlayer.nombre));
            myLogFile->writeInLog(0, "\n");
            //            cout << "Nombre jugador: " << string(myPlayer.nombre) << endl;


            //Cuando es un jugador recargado : llamo a json, saco el viejo del vector y agrego al vector.
            int np = playerAlreadyExist(string(myPlayer.nombre));
            if (np > 0) {//va a recargar un jugador
                //                cout << "[1] Ya era usuario, se recargara su partida" << endl;
                myLogFile->writeInLog(1, "[1] Ya era usuario, se recargara su partida\n");

                struct Element myStruct;
                myStruct = this->reloadPlayer(string(myPlayer.nombre));
                Player* pP = new Player(this->server, socket, this->objFact, np, myStruct.x, myStruct.y, myPlayer.nombre);

                this->waitingList.push_back(pP);

                this->initPlayer(*pP); //primer paquete: escenario + otros players

                pP->setUbicDyn(myStruct.ubic);
                // TODO: CHEQUEAR QUE LO ACOMODE CORRECTAMENTE Y SE VEA
                // elimino el player viejo..
                vector<WorldElement*>::iterator itErase = this->dynamicBodys.begin();
                this->dynamicBodys.erase(itErase + myStruct.ubic);

                // agrego en su posicion el player nuevo
                vector<WorldElement*>::iterator itInsert = this->dynamicBodys.begin();
                this->dynamicBodys.insert(itInsert + myStruct.ubic, pP);

                if (pP->isInit()) {//Si recibi el ok del cliente creo hilos y updeteo elementos y el character
                    this->sendInitialWorld(pP);
                }

                if (this->readyToReload) {
                    pP->runThreadRecv();
                    pP->runThreadSend();
                    pP->runThreadPulse();
                }

            } else {//Cuando es un nuevo jugador: creo el jugador y lo agrego al vector
                // Valido que pueda aceptar jugadores nuevos
                if (!(this->reloadLevel)) {
                    myLogFile->writeInLog(1, "[1] Es un juegador nuevo, se creara una partida\n");

                    this->createPlayer(socket, myPlayer);

                } else {
                    myLogFile->writeInLog(0, "[0] El limite de jugadores se ha alcanzado ya. No se aceptará al jugador\n");
                    //cout << "refuseeeeeeeeeeeeeeeeeeeeeeeeeeeeee" << endl;
                    struct ContenedorSocket data;
                    data.socket = socket;
                    data.player = myPlayer;
                    this->futurePlayers.push_back(data);
                    this->refusePlayer(socket);
                }
            }
        }
    }

    myLogFile->writeInLog(1, "[1] Finaliza escucha de clientes\n");
    //    cout << "Finaliza escucha.. No mas clientes disponibles" << endl;
}

void MundoSBS::refusePlayer(int socket) {
    struct Pantalla window;
    window.type = 'X';
    int lenWindow = sizeof (window);
    int k = this->getServer().sendAll(socket, &window, lenWindow);
}

void MundoSBS::sendPlayer() {
    if (this->players.size() != 0) {
        struct NewPlayer newPlayer;
        newPlayer.characterId = this->waitingList.front()->getCharacterId();

        char myName [8];
        strcpy(myName, this->waitingList.front()->getName().c_str());
        strcpy(newPlayer.nombre, myName);

        newPlayer.score = this->waitingList.front()->getScore();
        newPlayer.lifes = this->waitingList.front()->getLifes();

        //        cout << "sending player " << newPlayer.nombre << endl;
        int len = sizeof (newPlayer);
        for (list <Player*>::iterator it = this->players.begin(); it != this->players.end(); ++it) {
            Player *player = *it;

            int k = this->getServer().sendAll(player->getSocket(), &newPlayer, len);
            if (k == ERROR) {
                myLogFile->writeInLog(2, "[2] Error interno del socket al enviar info de Nuevo Jugador\n");
            }
            if (k == OFF) {
                myLogFile->writeInLog(1, "[1] Se desconecto el cliente mientras se le enviaba la info del Nuevo Jugador\n");
            }
        }
    }
}

void MundoSBS::createPlayer(int socket, struct Jugador myPlayer) {

    int characterId;
    if (this->marioAvailable) {
        characterId = 1;
    } else if (this->yoshiAvailable) {
        characterId = 2;
    } else if (this->luigiAvailable) {
        characterId = 3;
    } else if (this->tazAvailable) {
        characterId = 4;
    }

    cout << "NUEVO JUGADOR " << endl;
    Player *player = new Player(this->server, socket, this->objFact, characterId, this->data->getPlayerXLocation(characterId), this->data->getPlayerYLocation(characterId), myPlayer.nombre);

    this->initPlayer(*player); //primer paquete.

    if (player->getCharacterId() == 1) {
        this->marioAvailable = false;
    } else if (player->getCharacterId() == 2) {
        this->yoshiAvailable = false;
    } else if (player->getCharacterId() == 3) {
        this->luigiAvailable = false;
    } else if (player->getCharacterId() == 4) {
        this->tazAvailable = false;
    }

    this->waitingList.push_back(player);

    // si vec 0-n => size n+1 .. n+1 va a ser la nueva pos del elem pusheado            
    player->setUbicDyn(this->dynamicBodys.size());
    this->dynamicBodys.push_back(player);

    if (player->isInit()) {
        this->sendInitialWorld(player);
    }

}

int MundoSBS::initPlayer(Player & player) {//Envia el escenario + los objetos y recibe el OK del cliente
    if (!player.isInit()) {//si el cliente no fue inicializado                    

        // encapsulo info de pantalla + cantidad de elem en el mundo
        struct Pantalla window;
        int id, x, y;
        window.type = ID_WINDOW;
        window.pxWidth = this->data->getPixelWidth();
        window.pxHeight = this->data->getPixelHeight();
        window.luWidth = this->data->getLogicalUnitWidth();
        window.luHeight = this->data->getLogicalUnitHeight();
        window.characterId = player.getCharacterId();
        window.maxPlayers = this->maxPlayers;
        window.reloadLevel = this->reloadGame;

        vector<struct ObjectInit> message;

        for (int i = 0; i < this->worldObjects.size(); i++) {
            struct ObjectInit obj = this->worldObjects.at(i);
            message.push_back(obj);
        }

        window.elements = message.size();

        //envio la pantalla con la cant de elementos en el mundo.
        int lenWindow = sizeof (window);
        int k = this->getServer().sendAll(player.getSocket(), &window, lenWindow);
        if (k == ERROR) {
            myLogFile->writeInLog(2, "[2] Error interno del socket al enviar info de Pantalla\n");
        }
        if (k == OFF) {
            myLogFile->writeInLog(1, "[1] Se desconecto el cliente mientras se le enviaba la info de Pantalla\n");
        }

        //envio los elementos del mundo
        int aux = 0;
        for (int i = 0; i < message.size(); i++) {
            struct ObjectInit object = message.at(i);
            int len = sizeof (object);
            int j = this->getServer().sendAll(player.getSocket(), &object, len);
            if (j == ERROR) {
                myLogFile->writeInLog(2, "[2] Error interno del socket al enviar info del objeto id ");
                myLogFile->writeInLog(2, to_string(object.ubicDyn));
                myLogFile->writeInLog(2, " del Mapa\n");
                //                cout << "#ERROR-LOG: Error al enviar un objeto" << endl;
                break;
            }
            if (j == OFF) {
                myLogFile->writeInLog(1, "[1] Se desconecto el cliente mientras se le enviaba la info del Mapa\n");
                //                cout << "#ERROR-LOG se desconecto el cliente" << endl;
            } else {
                aux += j;
            }
        }

        // envio los jugadores conectados hasta el momento
        int lenPlayers = 0;
        for (list <Player*>::iterator it = this->players.begin(); it != this->players.end(); ++it) {
            Player *itPlayer = *it;

            if (itPlayer->isInit()) {
                lenPlayers++;
            }
        }
        if (lenPlayers == 0) {
            //            cout << "ENVIO CON LENPLayers vacio" << endl;
            struct NewPlayer newPlayer;
            newPlayer.characterId = VACIO;
            newPlayer.connected = 0;

            int len = sizeof (newPlayer);

            int j = this->getServer().sendAll(player.getSocket(), &newPlayer, len);
            if (j == ERROR) {
                myLogFile->writeInLog(2, "[2] Error interno del socket al enviar info de jugadores conectados.\n");
            }
            if (j == OFF) {
                myLogFile->writeInLog(1, "[1] Se desconecto el cliente mientras se le enviaba la info de jugadores conectados\n");
            }

        } else {
            //            cout << "ENVIO CON LENPLayers NO vacio" << endl;
            for (list <Player*>::iterator it = this->players.begin(); it != this->players.end(); ++it) {
                Player *itPlayer = *it;

                if (itPlayer->isInit()) {
                    struct NewPlayer newPlayer;
                    newPlayer.characterId = itPlayer->getCharacterId();
                    newPlayer.score = itPlayer->getScore();
                    newPlayer.lifes = itPlayer->getLifes();
                    newPlayer.connected = lenPlayers;

                    char myName [8];
                    strcpy(myName, itPlayer->getName().c_str());
                    strcpy(newPlayer.nombre, myName);

                    int len = sizeof (newPlayer);
                    //                    cout << "sent player (initPlayer): " << newPlayer.characterId << " " << newPlayer.nombre << endl;

                    int j = this->getServer().sendAll(player.getSocket(), &newPlayer, len);
                    if (j == ERROR) {
                        myLogFile->writeInLog(2, "[2] Error interno del socket al enviar info de jugadores conectados.\n");
                        break;
                    }
                    if (j == OFF) {
                        myLogFile->writeInLog(1, "[1] Se desconecto el cliente mientras se le enviaba la info de jugadores conectados\n");
                    }
                }
            }
        }
        // recibo mensaje de cliente que llego todo OK
        int num;
        int leng = sizeof (num);
        int time = 4;
        this->getServer().recvTimeOut(player.getSocket(), &num, leng, time);
        if (num == 0) { //todo ok
            myLogFile->writeInLog(1, "[1] Se recibió mensaje de confirmación del cliente\n");
            player.setInit(true);
        }
    }
}

void MundoSBS::getConection() {

    this->running = true;
    std::thread thread(&MundoSBS::startConection, this);
    std::swap(thread, this->threadConection);
}

list <Player*> *MundoSBS::getPlayers() {
    return &this->players;
}

ServerSocket MundoSBS::getServer() {
    return this->server;
}

struct sockaddr_in MundoSBS::getClientAddr() {
    return this->clientAddress;
}

b2World * MundoSBS::getWorld() {
    return this->world;
}

void MundoSBS::sendInitialWorldStatics(Player * player) {
    int size = this->staticBodys.size();
    int cont = 0;
    for (int j = 0; j < size; j++) {
        struct ObjectInit obj = this->staticBodys.at(j)->getData();
        obj.cantElementosEnviados = size + this->dynamicBodys.size();

        if (!((obj.objectId == 0) && (obj.idCharacter == 0))) {
            if (obj.idCharacter == VACIO) {
                if (!(obj.objectId < 0)) {
                    if (!(obj.idCharacter > 9)) {
                        player->pushObjects(obj);
                        cont++;
                    }
                }
            } else {
                if (obj.objectId == 0) {
                    if ((obj.idCharacter == 1) || (obj.idCharacter == 2) || (obj.idCharacter == 3) || (obj.idCharacter == 4) || (obj.idCharacter == 11) || (obj.idCharacter == 12) || (obj.idCharacter == 21)) {
                        player->pushObjects(obj);
                        cont++;
                    }
                }
            }
        }
    }
}

void MundoSBS::sendInitialWorld(Player * player) {
    int size = this->dynamicBodys.size();
    int cont = 0;
    for (int j = 0; j < size; j++) {
        struct ObjectInit obj = this->dynamicBodys.at(j)->getData();
        obj.cantElementosEnviados = size + this->staticBodys.size();

        if (!((obj.objectId == 0) && (obj.idCharacter == 0))) {
            if (obj.idCharacter == VACIO) {
                if (!(obj.objectId < 0)) {
                    if (!(obj.idCharacter > 9)) {
                        player->pushObjects(obj);
                        cont++;
                    }
                }
            } else {
                if (obj.objectId == 0) {
                    if ((obj.idCharacter == 1) || (obj.idCharacter == 2) || (obj.idCharacter == 3) || (obj.idCharacter == 4) || (obj.idCharacter == 11) || (obj.idCharacter == 12) || (obj.idCharacter == 21)) {
                        player->pushObjects(obj);
                        cont++;
                    }
                }
            }
        }

    }
}

void MundoSBS::setUpdatedData(Player * player) {


    int size = this->dynamicBodys.size();
    int cont = 0;
    for (int j = 0; j < size; j++) {
        struct ObjectInit obj = this->dynamicBodys.at(j)->getData();
        //        if ((obj.idCharacter != VACIO))
        //        cout << "tengo   " << obj.idCharacter << " " << obj.objectId << " " << obj.level << endl;
        if (!this->dynamicBodys.at(j)->getAreEquals()) {
            //            cout << "sending   " << obj.idCharacter << " " << obj.objectId << " " << obj.level << endl;
            if (!((obj.objectId == 0) && (obj.idCharacter == 0))) {
                if (obj.idCharacter == VACIO) {
                    if (!(obj.objectId < 0)) {
                        if (!(obj.idCharacter > 9)) {
                            player->pushObjects(obj);
                            cont++;
                        }
                    }
                } else {
                    if (obj.objectId == 0) {
                        if ((obj.idCharacter == 1) || (obj.idCharacter == 2) || (obj.idCharacter == 3) || (obj.idCharacter == 4) || (obj.idCharacter == 11) || (obj.idCharacter == 12) || (obj.idCharacter == 21)) {
                            player->pushObjects(obj);
                            cont++;
                        }
                    }
                }
            }
        }
    }

    //shoot        
    for (list <Bullet*>::iterator it = this->bulletsList.begin(); it != this->bulletsList.end(); ++it) {
        cont++;
        Bullet *bullet = *it;
        struct ObjectInit dataBullet = bullet->getShape()->getData();
        //Envio los disparos a todos los personajes.
        for (list <Player*>::iterator itPlayer = this->players.begin(); itPlayer != this->players.end(); ++itPlayer) {
            Player* player = *itPlayer;
            if (dataBullet.bulletStat != BULLET_DEAD) {
                //                if (bullet->getCantidadDeEnviadosOld() <= 20) { //Cuando la bala se va al inframundo, es necesario que se cambie su estado para que no se 
                //envie siempre al cliente. Solucion, contadores al estilo de Paula Andrea.
                //                cout << "UbyDin: " << dataBullet.ubicDyn << "  size:" << this->bulletsList.size() << "  stat: " << dataBullet.bulletStat << endl;
                player->pushObjects(dataBullet);
                //                    bullet->incrementarEnvioOld();
                //                } else {
                //                    bullet->setStat(1);
                //                }

            }
        }
        //actualizo el estado de las balas 
        if (bullet->inConctacFloor() || bullet->inConctacEnemy() || bullet->inConctacBonus() || bullet->inConctacBoss()) { //entonces,tengo que eliminar                                 
            if (dataBullet.bulletStat == BULLET_DEAD) { //elimino de la lista de bulletList                
                if (bullet->getCantidadDeEnvios() <= 10) {
                    player->pushObjects(dataBullet);
                    bullet->incrementarEnvio();
                }
                //entonces elimino el elemento de la lista
                //                this->bulletsOld.push_back(bullet);

            } else { //elimino de box2D
                //                cout << "cantidad de element box2D: " << this->world->GetBodyCount() << endl;
                //                this->world->DestroyBody(bullet->getShape()->getObject()->getBody()); //elimina body.                

                //                this->world->DestroyBody(unElem->getBody());
                Dot *dot = new Dot(-100, -100);
                dot->dotPixelsToWorld();
                b2Vec2* pos = dot->getPos();
                bullet->getShape()->getObject()->getBody()->SetTransform(*pos, 0);
                delete dot;
                bullet->getShape()->getObject()->getBody()->SetType(b2_staticBody);


                bullet->setStat(1); //1: Dead, para eliminar el elemento de la lista.              
                //#NOTA: agregando estas lineas dejo de dibujar la bala cuando choca contra un enemigo o el piso.
                //                dataBullet = bullet->getShape()->getData();
                //                player->pushObjects(dataBullet);
            }

        } else {
            //lo marco como nuevo
            //muy feo esto, pero creo que funciona (por el momento)            
            if (dataBullet.bulletStat == 0) { //entonces aun no se envio al cliente lo envio
                bullet->setStat(2); //cambio su estado, a "viejo"                                
            }
        }
    }

    if (cont > 0) {
        struct ObjectInit fin;
        fin.idCharacter = ID_END_SEND;
        player->pushObjects(fin);
    }
}

void MundoSBS::checkChanges() {
    int size = this->dynamicBodys.size();
    for (int i = 0; i < size; i++) {
        this->dynamicBodys.at(i)->checkChanges();
    }
}

bool MundoSBS::arePlayersWaiting() {
    if (!this->waitingList.empty()) {
        return true;
    }
    return false;
}

bool MundoSBS::areFuturesPlayers() {
    if (!this->futurePlayers.empty()) {
        return true;
    }
    return false;
}

struct ContenedorSocket MundoSBS::getFirstFuturePlayer() {
    struct ContenedorSocket data = this->futurePlayers.front();
    this->futurePlayers.pop_front();

    return data;
}

void MundoSBS::addNewBonus(float posX, float posY) {
    for (int j = 0; j < this->bonus.size(); j++) {
        int i = rand() % this->bonus.size();
        if (!this->bonus.at(j)->isUsed) {
            this->bonus.at(j)->revive(posX, posY);
            break;
        }
    }
}

void MundoSBS::deleteBonus() {
    int size = this->bonus.size();
    for (int i = 0; i < size; i++) {
        Object* objBonus = this->bonus.at(i)->getObject();
        void* bonusDataVoid = objBonus->getBody()->GetUserData();
        int bonusData = *((int*) &bonusDataVoid);
        if (bonusData == TO_DELETE) {
            this->bonus.at(i)->kill();
        }
    }
}

void MundoSBS::deleteOldBonus() {
    int size = this->bonus.size();
    for (int i = 0; i < size; i++) {
        if ((this->bonus.at(i)->isUsed) && (this->bonus.at(i)->hasToDisappear())) {
            this->bonus.at(i)->kill();
        }
    }
}

void MundoSBS::killEnemy(Enemy * enemy) {
    //        this->world->DestroyBody(enemy->getBody());
    enemy->kill();
}

void MundoSBS::runThreads() {
    for (list <Player*>::iterator it = this->players.begin(); it != this->players.end(); ++it) {
        Player *itPlayer = *it;
        itPlayer->runThreadRecv();
        itPlayer->runThreadSend();
        itPlayer->runThreadPulse();
    }
}

void MundoSBS::actualizePlayerList() {
    int id = this->waitingList.front()->getCharacterId();
    for (list <Player*>::iterator it = this->players.begin(); it != this->players.end(); ++it) {
        Player *itPlayer = *it;
        if (itPlayer->getCharacterId() == id) {
            this->players.erase(it);
            break;
        }
    }
    this->players.push_back(this->waitingList.front());
    while (!this->players.back()->isInit()) {
        //        cout << "player NOOOOOOOOOOOOOOOOOOTTTTTT init!!!!!!!!!!!" << endl;
    }

    this->waitingList.pop_front();


    if (this->readyToReload) {
        this->players.back()->runThreadRecv();
        this->players.back()->runThreadSend();
        this->players.back()->runThreadPulse();
    }

}

//shoot

void MundoSBS::setBullets(SnowBall * snowBall) {
    //Bullet se guardan en un nuevo contenedor para enviar al cliente(no forma parte
    //de los objetos dinamicos).        
    //    cout << "this->bulletsList.size(): " << this->bulletsList.size() << endl;
    snowBall->getShape()->setUbicDyn(this->bulletsList.size());
    this->bulletsList.push_back(snowBall);
}

void MundoSBS::clean() {
    //    cout << "INI RECICLADO/LIMPIEZA DE OBJETOS DE BOX2D" << endl;
    //Elimino el piso del escenario viejo.
    //    int tamGround = this->ground.size();
    //    for (int i = 0; i < tamGround; i++) {
    //        WorldElement* unElem = this->ground.at(i);
    //        this->world->DestroyBody(unElem->getBody());
    //        delete unElem;
    //    }
    //Elminamos vector de objetos estaticos        
    //    cout << "ini this->staticBodys.size():" << this->staticBodys.size() << endl;
    int tam = this->staticBodys.size();
    for (int i = 0; i < tam; i++) {
        WorldElement* unElem = this->staticBodys.at(i);
        //                this->world->DestroyBody(unElem->getBody());
        Dot *dot = new Dot(-100, -100);
        dot->dotPixelsToWorld();
        b2Vec2* pos = dot->getPos();
        unElem->getBody()->SetTransform(*pos, 0);
        delete dot;
        unElem->getBody()->SetType(b2_staticBody);
        delete unElem;
    }

    //guardo los clientes en auxPlayers.
    int tam2 = this->dynamicBodys.size();
    for (int i = 0; i < tam2; i++) {
        WorldElement* unElem = this->dynamicBodys.at(i);
        if ((unElem->getData().idCharacter != VACIO)&&(unElem->getData().idCharacter < 10)) {
            for (list <Player*>::iterator it = this->players.begin(); it != this->players.end(); ++it) {
                Player* itPlayer = *it;
                if ((itPlayer->isInit()) && (unElem->getData().stateCharacter != DEAD)) {
                    if (itPlayer->getCharacterId() == unElem->getData().idCharacter) {
                        auxPlayers.push_back(unElem);
                    }
                } else {
                    // el player que estaba DEAD lo mando al inframundo
                    //                    Dot *dot = new Dot(-100, -100);
                    //                    dot->dotPixelsToWorld();
                    //                    b2Vec2* pos = dot->getPos();
                    //                    unElem->getBody()->SetTransform(*pos, 0);
                    //                    delete dot;
                    //                    unElem->getBody()->SetType(b2_staticBody);
                    //                    delete unElem;
                }
            }
        } else {
            //            this->world->DestroyBody(unElem->getBody());
            Dot *dot = new Dot(-100, -100);
            dot->dotPixelsToWorld();
            b2Vec2* pos = dot->getPos();
            unElem->getBody()->SetTransform(*pos, 0);
            delete dot;
            unElem->getBody()->SetType(b2_staticBody);
            delete unElem;
        }
    }

    int tam5 = this->dynamicBodys.size();
    for (int i = 0; i < tam5; i++) {
        this->dynamicBodys.pop_back();
    }

    int tam6 = this->staticBodys.size();
    for (int i = 0; i < tam6; i++) {
        this->staticBodys.pop_back();
    }

    //limpio vector de enemigos 1
    int tamEnemigos = this->fireShooterEnemy.size();
    for (int i = 0; i < tamEnemigos; i++) {
        this->fireShooterEnemy.pop_back();
    }

    //limpio vector de enemigos 2
    int tamEnemigos2 = this->standardEnemy.size();
    for (int i = 0; i < tamEnemigos2; i++) {
        this->standardEnemy.pop_back();
    }

    //limpio vector de bonus
    int tamBonus = this->bonus.size();
    for (int i = 0; i < tamBonus; i++) {
        this->bonus.pop_back();
    }

    for (list <Bullet*>::iterator it = this->bulletsList.begin(); it != this->bulletsList.end(); ++it) {
        Bullet *bullet = *it;
        if (bullet->getCantidadDeEnvios() == 0) {
            this->world->DestroyBody(bullet->getShape()->getBody());
        }
        //        delete bullet;
    }

    //limpio el vector bullet
    int tamBullet = this->bulletsList.size();
    for (int i = 0; i < tamBullet; i++) {
        this->bulletsList.pop_back();
    }

    //    cout << "FIN RECICLADO/LIMPIEZA DE OBJETOS DE BOX2D" << endl;

}

void MundoSBS::deleteWorld() {
    delete this->world;
}

void MundoSBS::createWorld() {
    //init World.
    b2Vec2 gravity(0.0f, WORLD_GRAVITY);
    b2World *world = new b2World(gravity);
    this->world = world;

    this->objFact = new ObjFactory(*this->world, this->data2->getLogicalUnitWidth(), this->data2->getLogicalUnitHeight());
    Rectangle *ground = new Rectangle(objFact, true, (this->data->getLogicalUnitWidth()) / 2, this->data->getLogicalUnitHeight(), this->data->getLogicalUnitWidth(), this->data->getLogicalUnitHeight()*0.066, 10, 0, 0);
    ground->changeGroupIndex(GROUPINDEXEDGE);
    this->ground.push_back(ground);
    Rectangle *ceiling = new Rectangle(objFact, true, (this->data->getLogicalUnitWidth()) / 2, 0, this->data->getLogicalUnitWidth(), 2, 10, 0, 0);
    ceiling->changeGroupIndex(GROUPINDEXEDGE);
    this->ground.push_back(ceiling);
    Rectangle *leftWall = new Rectangle(objFact, true, -40, (this->data->getLogicalUnitHeight()) / 2, 80, this->data->getLogicalUnitHeight(), 10, 0, 0);
    leftWall->changeGroupIndex(GROUPINDEXEDGE);
    this->ground.push_back(leftWall);
    Rectangle *rightWall = new Rectangle(objFact, true, this->data->getLogicalUnitWidth() + 40, (this->data->getLogicalUnitHeight()) / 2, 80, this->data->getLogicalUnitHeight(), 10, 0, 0);
    rightWall->changeGroupIndex(GROUPINDEXEDGE);
    this->ground.push_back(rightWall);

}

void MundoSBS::setReloadLevel(bool state) {
    this->reloadLevel = state;

    // para enviar a los futuros usr
    this->reloadGame = 1;
}

int MundoSBS::cantPlayersInit() {
    int cant = 0;
    for (list <Player*>::iterator it = this->players.begin(); it != this->players.end(); ++it) {
        Player *myP = *it;
        if (myP->isInit()) {
            cant++;
        }
    }
    return cant;
}

bool MundoSBS::gameOver() {
    int cant = 0; // para watchers
    int cont = 0; // para desconectados

    for (list <Player*>::iterator it = this->players.begin(); it != this->players.end(); ++it) {
        Player *myP = *it;
        if (myP->isWatching()) {
            cant++;
        } else if (!(myP->isInit())) {
            cont++;
        }
    }

    if (cant == this->players.size()) {
        return true;
    } else if (cont == this->players.size()) {
        return true;
    } else if ((cant + cont) == this->players.size()) {
        return true;
    }

    return false;
}

list <Bullet*> MundoSBS::getBulletList(){
    return this->bulletsList;
}